package com.ly.mp.busicen.rule.instrumentation.plugin;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.ly.mp.busicen.rule.flow.ActionContainer;
import com.ly.mp.busicen.rule.flow.Fragment;
import com.ly.mp.busicen.rule.flow.action.ActionExecuteBase;
import com.ly.mp.busicen.rule.flow.engine.db.BusicenSqlMapper;

import io.seata.core.context.RootContext;

public class ApiRealEventPublish implements IApiRealEventPublish,ApplicationContextAware {
	
	private final static Logger log = LoggerFactory.getLogger(ApiRealEventPublish.class);
	
	ApiRealHandlerContainer apiRealHandlerContainer;
	
	ApplicationContext applicationContext;
	
	ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
	
	public ApiRealEventPublish(ApiRealHandlerContainer container,ActionContainer actionContainer) {
		this.apiRealHandlerContainer = container;
		this.actionContainer = actionContainer;
	}
	
	ActionContainer actionContainer;
	
	@PostConstruct
	void init() {
		Map<String, IApiRealHandlerRegister> types = applicationContext.getBeansOfType(IApiRealHandlerRegister.class);
		types.values().forEach(m->m.regist(apiRealHandlerContainer));
	}
	
	@Override
	public void pushResult(String flow, Map<String, Object> data) {
		//事务暂停
		boolean inGts = RootContext.inGlobalTransaction();
		String xid=null;
		if (inGts) {
			xid = RootContext.unbind();
		}
		try {
			apiRealHandlerContainer.handlers(flow).forEach(m->{
				if (m.isSync()) {
					m.getHandler().handle(flow, data);					
				}else {
					executorService.execute(()->m.getHandler().handle(flow, data));
				}				
			});
		} catch (Exception e) {
			log.error("规则引擎实时推送处理异常",e);
			handleExcept(flow, data);
			throw e;
		}finally {
			//事务恢复
			if (inGts) {
				RootContext.bind(xid);
			}
		}		
	}
	
	public void handleExcept(String flow, Map<String, Object> data) {
		Optional<Fragment> optional = actionContainer.getFragments().stream().filter(m->"BUPK_INSERT_EXCEPT".equals(m.getRuleCode())).findFirst();
		String sql;
		if (optional.isPresent()) {
			sql=optional.get().getContent();
		}else {
			RuntimeException exception = new RuntimeException("未配置插入消息表规则【BUPK_INSERT_EXCEPT】");
			throw exception;
		}
		data.put("flow", flow);					
		ActionExecuteBase.wrapperUserData(data);
		BusicenSqlMapper busicenSqlMapper = BusicenSqlMapper.create();
		busicenSqlMapper.insert(sql, data);
	}
	
	

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext= applicationContext;		
	}


}
